var context;
var canvas;
var titleSound = new AudioFX('Sounds/TitleScreenLoop.wav', {loop: true});
var endLevelSound = new AudioFX('Sounds/LevelCompleted.wav');
var bounceSound1 = new AudioFX('Sounds/Bounce1.wav');
var bouncesound2 = new AudioFX('Sounds/Bounce2.wav');
var deathSound = new AudioFX('Sounds/DeathSound.wav');
// Credit to songs:
//
// http://www.freesound.org/people/reacthor/sounds/130982/ - Title Screen Loop
//
// http://www.freesound.org/people/zgump/sounds/128129/ - Level Completed
//
// http://www.freesound.org/people/Rob10/sounds/132584/ - Bounce 1
//
// http://www.freesound.org/people/Rob10/sounds/132582/ - Bounce 2
//
// http://www.freesound.org/people/xjhall/sounds/132292/ - Dead Sound
//
// All songs licensed with Creative Commons
var gameInfo = {};

var canvasHeight = 640;
var canvasWidth = 1280;
var gravity = 0.2;
var boostFactor = 1.1;
var playerAccel = 0.1;
var maxVelocity = 4;
var maxBoostVelocity = 8;
var playerJump = 6;

var params = defaultParams();

var objects = [];
var dynamic_objects = [];
var static_objects = [];
var trigger_objects = [];
var hud_objects = [];
var player;

var gravityInverted = false;
var shouldInvertGravity = false;

// is player dying?
var playerDying = false;

function resetKeyState() {
    keyState = [];
    for (var i = 0; i < 200; i++) {
        keyState[i] = false;
    }
}

function defaultParams() {
    return {
        minStickiness: 0,
    };
}

function updateSliders() {
    for (var i = 0; i < sliders.length; i++) {
        var s = sliders[i];
        s.input.val(params[s.param]);
        s.slider.slider("option", "value", params[s.param]);
    }
}

function changeParams(p) {
    params = p;
    updateSliders();
}

var keyId = {
    left: [65, 37],
    up: [38, 87],
    jump: [38, 87],
    right: [39, 68],
    down: [40, 83],
    gravity: [71],
    boost: [66],
    reset: [82],
	swap: [192],
	
};

function getKeyState(key) {
    for (var i = 0; i < key.length; i++) {
        if (keyState[key[i]]) return true;
    }
    return false;
}

function inArray(v, arr) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == v) return true;
    }
    return false;
}

var passState = 0;
function checkPassword(keyCode) {
    var pword = [72, 79, 66, 66, 69, 83];
	pword = [72, 72, 72];

    if (keyCode == pword[passState]) passState++;
    else passState = 0;

    if (passState == pword.length) {
		nextLevel();
		countDown = 0;
        passState = 0;
    }
}

function keyup(event){
    console.log("keyup: " + event.keyCode);
    if (inArray(event.keyCode, keyId.up) && getKeyState(keyId.up)) {
        player.shouldJump = false;
    }
    keyState[event.keyCode] = false;
}

function keydown(event){
    console.log("keydown: " + event.keyCode);
    checkPassword(event.keyCode);
    switch(event.keyCode) {
        case 82: // reset (r)
            if (!getKeyState(keyId.reset)) {
                shouldReset = true;
            }
            break;
            //left
		case 192: // swap
			if (!getKeyState(keyId.swap)) {
				swapWorld();
			}
			break;
        case 37:
        case 65:
            break;

            //up
        case 38:
        case 87:
            if (!getKeyState(keyId.jump)) {
                player.shouldJump = true;
            }
            break;
            //right
        case 39:
        case 68:
            break;

            //down
        case 40:
        case 83:
            break;

        case 81: // q
            break;
		
        case 71: // gravity (g)
            if (!getKeyState(keyId.gravity)) {
                shouldInvertGravity = true;
            }
            break;
        case 66: // boost (b)
            break;
    }
    keyState[event.keyCode] = true;
}

var in2dWorld = false;

function swapWorld(){
	var d2 = document.getElementById("2dGame");
	var d3 = document.getElementById("3dGame");
	if(d2.style.display === "none"){
		d2.style.display = "inline";
		d3.style.display = "none";
        in2dWorld = true;
	}
	else{
		d2.style.display = "none";
		d3.style.display = "inline";
        in2dWorld = false;
	}
	
	
}

function displayTitle() {
    var destX = 0;
    var destY = 0;
 
    var imageObj = new Image();
    imageObj.src = "titlescreen.jpg";
	titleSound.play();
    imageObj.onload = function(){
        gameInfo.context.drawImage(imageObj, destX, destY);
    };
}

var keydownHandler = function() { };
var keyupHandler = function() { };


$(document).ready(function() {
	document.getElementById("gameInfo");

	$(document).keydown(function(ev) { keydownHandler(ev); });
    $(document).keyup(function(ev) { keyupHandler(ev); });

    canvas = document.getElementById("gameCanvas");
    context = canvas.getContext("2d");

    gameInfo.canvas = document.getElementById("gameInfo");
    gameInfo.context = gameInfo.canvas.getContext("2d");
	
	displayTitle();
    //titleSound.play();
	keyupHandler = function() { startGame(); };
    //startGame();
	
	

})


function startGame() {

	keydownHandler = keydown;
    keyupHandler = keyup;
	
	levelNum = 0;
	webGLStart();

	water = makeWater(-400, canvasHeight - 50, canvasWidth + 800, 1200);

    setupWorld();

    start();
}

var lastUpdateTime = 0;
var lastDrawTime = 0;
var fps = 20;
var countDown = 500; // for the reset function 

function start() {
    
    resetGame(defaultParams());
    run();
}

function resetGame(newParams) {
    shouldReset = false;
    gameStart = new Date().getTime();
    lastUpdateTime = new Date().getTime();
    lastDrawTime = new Date().getTime();
    score = 0;
    resetKeyState();
    changeParams(newParams);
    setupGame();
}

function setupGame() {

}

function applyGravity(obj) {
    var g = [0, gravityInverted ? -gravity : gravity];
    if (obj.stuck) {
        var decomp = normalDecompose(g, obj.stuck_to);
        if (decomp[0] > 0.001) {
            g = add(decomp[2], scale(0.01, decomp[1]));
        }
    } 
    obj.d[0] += g[0];
    obj.d[1] += g[1];
}

function acceleratePlayer(v) {
    var a = [v * playerAccel, 0];
    if (player.stuck) {
        if (Math.abs(v) < 0.001) {
            var decomp = normalDecompose(player.d, player.stuck_to);
            if (decomp[0] > -0.0001) {
                a = add(a, scale(-.02, decomp[2]));
            }
        } else {
            var decomp = normalDecompose(a, player.stuck_to);
            if (decomp[0] > -0.00001) {
                a = decomp[2];
            }
        }
    }
    var n = add(a, player.d);
    if ((Math.abs(n[0]) < maxVelocity) || 
            (Math.abs(player.d[0]) > maxVelocity && Math.abs(n[0]) < Math.abs(player.d[0]))) {
		player.d = n;
    }
}

function clear() {
    gameInfo.context.clearRect(0, 0, canvas.width, canvas.height);
    context.clearRect(0, 0, canvas.width, canvas.height);
}

function update_ex() {
    // update time left
    if (shouldReset == true) {
        countDown -= timeStep;
    }

    // if no time left, reset game
    if ((shouldReset && (countDown <= 0.1))) {
            objects = [];
            static_objects = [];
            dynamic_objects = [];
            setupWorld();
            shouldReset = false;
            countDown = 500;
    }

    minStickiness = 0;
    var move = (getKeyState(keyId.left) ? -1 : 0) + (getKeyState(keyId.right) ? 1 : 0);
    var shouldBoost = getKeyState(keyId.boost) &&
		(Math.abs(player.d[0]) > 0.0001) &&
		(Math.abs(move) < 0.0001 || (normalDecompose([move, 0], player.d)[0] < 0.0001));
    if (!shouldBoost) {
        acceleratePlayer(move);
    }
    if (player.stuck && (player.stuck_to[1] * (gravityInverted ? 1 : -1) > 0.01)) {
        if (shouldInvertGravity) {
            //gravityInverted = !gravityInverted;
        }
        if (shouldBoost) {
			var n = scale(boostFactor, player.d);
			var ln = length(n);
			if (ln > maxBoostVelocity) {
				n = scale(maxBoostVelocity / ln, n);
			}
			player.d = n;
            minStickiness = 10;
        }
        if (player.shouldJump) {
            player.d = add(player.d, scale(playerJump, player.stuck_to));
            player.shouldJump = false;
        }
    }
    shouldInvertGravity = false;

    for (var i = 0; i < dynamic_objects.length; i++) {
        var o = dynamic_objects[i];
        applyGravity(o);
    }

    update();
}

var timeStep = 10;
function run() {
    var steps = 0, maxSteps = 4; // 1000 / timeStep / maxSteps ~= min framerate
    while ((new Date().getTime() - lastUpdateTime > timeStep)
            && steps < maxSteps) {
        update_ex();
        lastUpdateTime += timeStep;
        steps++;
    }
    clear();
    draw();

    var dt = new Date().getTime() - lastDrawTime;
    lastDrawTime += dt;
    setTimeout(run, Math.max(5, 1000 / 60 - dt));
}
